package com.dfe.backend.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.compress.CompressUtil;
import cn.hutool.extra.compress.extractor.Extractor;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dfe.backend.common.bean.virtual.VirtualNode;
import com.dfe.backend.common.cache.CaffeineCache;
import com.dfe.backend.common.sax.scd.ScdData;
import com.dfe.backend.common.sax.scd.ied.ExtRef;
import com.dfe.backend.common.sax.spd.SpdData;
import com.dfe.backend.common.util.CalculateUtil;
import com.dfe.backend.common.util.XmlUtil;
import com.dfe.backend.common.websocket.client.WebSocketClient;
import com.dfe.backend.dao.DfeFileMapper;
import com.dfe.backend.entity.DfeFile;
import com.dfe.backend.service.DfeFileService;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.util.List;
import java.util.Map;

/**
 * 【描述】：针对表【dfe_file】的数据库操作Service实现
 *
 * @author Chang
 * @since 2025-08-01 14:51:23
 */
@Slf4j
@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class DfeFileServiceImpl extends ServiceImpl<DfeFileMapper, DfeFile> implements DfeFileService {

    CaffeineCache caffeineCache;

    WebSocketClient webSocketClient;

    @NonFinal
    @Value("${webservice.host}")
    private String webserviceHost;

    @NonFinal
    @Value("${file.uploadWinDirectory}")
    String uploadWinDirectory;

    @NonFinal
    @Value("${file.uploadLinuxDirectory}")
    String uploadLinuxDirectory;

    /**
     * 【描述】: 保存文件
     *
     * @param file     文件
     * @param fileType 文件类型
     * @return {@link String}
     * @throws Exception Exception
     * @author LiChang
     * @since 2025-8-4 8:41
     */
    @Override
    public String uploadZipFile(MultipartFile file, String fileType) throws Exception {
        // 获取文件扩展名
        String fileExtension = FilenameUtils.getExtension(file.getOriginalFilename());
        // 获取不带扩展名的文件名
        String fileNameWithoutExtension = FilenameUtils.removeExtension(file.getOriginalFilename());
        // 拼接文件名
        String fileName = fileNameWithoutExtension + "_" + System.currentTimeMillis() + "." + fileExtension;

        String osName = System.getProperty("os.name").toLowerCase();
        String uploadDirectory;
        if (osName.contains("win")) {
            uploadDirectory = uploadWinDirectory + "/" + fileType;
        } else {
            uploadDirectory = uploadLinuxDirectory + "/" + fileType;
        }

        String filePath = uploadDirectory + File.separator + fileName;
        File dest = new File(filePath);

        // 检查上传路径是否存在，如果不存在则创建
        File uploadDir = new File(uploadDirectory);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs(); // 创建文件夹
        }
        file.transferTo(dest);

        // 实例化ZipFile对象
        Extractor extractor = CompressUtil.createExtractor(CharsetUtil.defaultCharset(), dest);
        // 解压压缩包
        extractor.extract(FileUtil.file(uploadDirectory));
        // 打开文件夹
        File directory = new File(uploadDirectory);
        String directoryPath = "";
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                String endFileType = "." + fileType;
                for (File tempFile : files) {
                    if (tempFile.isFile() && tempFile.getName().endsWith(endFileType)) {
                        directoryPath = uploadDirectory + "/" + tempFile.getName();
                    }
                }
            }
        }
        return directoryPath;
    }

    /**
     * 【描述】: 分析文件
     *
     * @param filePath 文件路径
     * @param fileType 文件类型
     * @author LiChang
     * @since 2025-8-13 14:10
     */
    @Override
    @Async("taskExecutor")
    public void analyseFile(String filePath, String fileType) {
        if ("scd".equals(fileType)) {
            log.info("==========================异步SCD文件分析开始==========================");
            // 记录开始时间
            Instant start = Instant.now();
            // scd文件分析处理开始
            ScdData scdData = XmlUtil.analyseScd(filePath);
            CalculateUtil.calExecuteTime(start, "SCD分析");
            // 缓存存储
            if (scdData != null) {
                // 存储IED信息缓存
                caffeineCache.iedInfoListCache().put("scd", scdData.getIedInfoList());

                // IED名称与虚拟对象映射
                Map<String, List<VirtualNode>> iedVirtualNodeMap = scdData.getIedVirtualNodeMap();
                iedVirtualNodeMap.forEach((iedName, virtualNodeList) -> caffeineCache.iedVirtualNodeCache().put(iedName, virtualNodeList));

                // IED名称与对应关系映射
                Map<String, List<ExtRef>> iedExtRefMap = scdData.getIedExtRefMap();
                iedExtRefMap.forEach((iedName, extRefList) -> caffeineCache.iedExtRefCache().put(iedName, extRefList));

                // 真实端口关系映射
                Map<String, String> realPortMap = scdData.getRealPortMap();
                realPortMap.forEach((key, port) -> caffeineCache.realPortCache().put(key, port));
                log.info("SCD缓存预存执行完毕！");
            }
            log.info("==========================异步SCD文件分析完成==========================");
        } else if("spd".equals(fileType)){
            log.info("==========================异步SPD文件分析开始==========================");
            SpdData spdData = XmlUtil.analyseSpd(filePath);
            if (spdData != null) {
                // 存储SPD信息
                caffeineCache.spdDataCache().put("spd", spdData);
            }
            log.info("==========================异步SPD文件分析完成==========================");
        }

    }


    /**
     * 【描述】: 订阅IED信息
     *
     * @author LiChang
     * @since 2025-8-12 16:32
     */
    private void subscribeIedInfo() {
        try {


        } catch (Exception e) {
            log.error("IED信息订阅失败！", e);
        }
    }

    /**
     * 【描述】: 删除文件
     *
     * @param id 文件ID
     * @return {@link boolean}
     * @author LiChang
     * @since 2025-8-8 14:33
     */
    @Override
    public boolean deleteFile(Integer id) {
        DfeFile dfeFile = this.getById(id);
        if (dfeFile == null) {
            return false;
        }
        String fileType = dfeFile.getFileType();
        if ("scd".equals(fileType) || "spd".equals(fileType)) {
            String path;
            if (System.getProperty("os.name").toLowerCase().contains("win")) {
                path = uploadWinDirectory + "/scd";
            } else {
                path = uploadLinuxDirectory + "/scd";
            }
            // 获取待删除全部文件路径
            Path dir = Paths.get(path);
            try {
                if (Files.exists(dir) && Files.isDirectory(dir)) {
                    Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            // 删除文件
                            Files.delete(file);
                            return FileVisitResult.CONTINUE;
                        }

                        @Override
                        public FileVisitResult visitFileFailed(Path file, IOException exc) {
                            // 访问权限错误
                            return FileVisitResult.CONTINUE;
                        }
                    });
                }
            } catch (Exception e) {
                log.error("删除文件失败: {}", e.getMessage());
            }
            // 重置缓存
            caffeineCache.iedInfoListCache().invalidateAll();
            caffeineCache.iedVirtualNodeCache().invalidateAll();
            caffeineCache.iedExtRefCache().invalidateAll();
            return this.removeById(id);
        } else {
            // 删除指定路径文件
            File file = new File(dfeFile.getFileUrl());
            if (file.exists()) {
                return file.delete();
            }
        }
        return false;
    }


}




